package com.inexas.cu.klient.register;

import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import java.util.*;
import org.easymock.*;
import org.junit.*;
import com.google.inject.*;
import com.inexas.cu.client.eventbus.*;
import com.inexas.cu.client.mvp.*;
import com.inexas.cu.client.mvp.Observer;
import com.inexas.cu.client.mvp.Member.*;
import com.inexas.cu.client.register.*;

public class UtRegistration {
	private interface ObserverAndSource extends Observer, Source {
		//
	}

	private final static String accountName = "account";
	private final static String password = "password";
	private SignInPresenter presenter;
	private View<SignInPm> view;
	private EventBus eventBus;
	private SignInPm pm = new SignInPm("", "");
	private Actuator signInActuator = pm.getSignInActuator();
	private Property<String> accountNameProperty = pm.getAccountName();
	private Property<String> passwordProperty = pm.getPassword();

	public class TestModule extends AbstractModule {

		@Override
		protected void configure() {
			bind(SignInPresenter.class);
		}

		@SuppressWarnings("unchecked")
        @Provides
		View<SignInPm> provideMySignInView() {
			// !todo This probably needs some work
			view = createMock(View.class);
			return view;
		}

		@Provides
		EventBus provideEventBus() {
			eventBus = createMock(EventBus.class);
			return eventBus;
		}

	}

	@Before
	public void setup() {
		final Injector factory = Guice.createInjector(new TestModule());
		presenter = factory.getInstance(SignInPresenter.class);
		pm = new SignInPm("", "");
		accountNameProperty = pm.getAccountName();
		passwordProperty = pm.getPassword();
		signInActuator = pm.getSignInActuator();
	}

	@Test
	public void basicOperation() {
		presenter.setSignInPm(pm);

		assertEquals(signInActuator.getAccess(), Access.READONLY);
		accountNameProperty.setValue(presenter, accountName);
		assertEquals(signInActuator.getAccess(), Access.READONLY);
		passwordProperty.setValue(presenter, password);
		assertEquals(signInActuator.getAccess(), Access.READWRITE);
		accountNameProperty.setValue(presenter, " ");
		assertEquals(signInActuator.getAccess(), Access.READONLY);
		passwordProperty.setValue(presenter, null);
		assertEquals(signInActuator.getAccess(), Access.READONLY);
	}

	@Test
	public void initialization() {
		accountNameProperty.setValue(presenter, accountName);
		passwordProperty.setValue(presenter, password);
		presenter.setSignInPm(pm);

		assertEquals(signInActuator.getAccess(), Access.READWRITE);
	}

	@Test
	public void signIn() {
		final Capture<SignIn> capturedSignIn = new Capture<SignIn>();
		eventBus.fireEvent(capture(capturedSignIn));
		replay(eventBus);

		accountNameProperty.setValue(presenter, accountName);
		passwordProperty.setValue(presenter, password);
		presenter.setSignInPm(pm);
		signInActuator.trigger(view);
		verify(eventBus);
		final SignIn signIn = capturedSignIn.getValue();
		assertEquals(signIn.getAccountName(), accountName);
		assertEquals(signIn.getPassword(), password);
	}

	@Test
	public void eventDirectCircularity() {
		final ObserverAndSource observer = createMock(ObserverAndSource.class);
		accountNameProperty.addObserver(observer);
		replay(observer);
		accountNameProperty.setValue(observer, "Whatever");
		verify(observer);
	}

	@Test
	public void eventAgrregatedCircularity() {
		final ObserverAndSource observer = createMock(ObserverAndSource.class);
		pm.addObserver(observer);
		replay(observer);
		accountNameProperty.setValue(observer, "Whatever");
		verify(observer);
	}

	@Test
	public void validation() {
		accountNameProperty.setValue(presenter, accountName);
		assertNull(accountNameProperty.getValidationErrors());

		accountNameProperty.setValue(presenter, "far, far, far, far, too long");
		final List<ValidationError> errors = accountNameProperty.getValidationErrors();
		assertTrue(errors != null && errors.size() > 0);
	}

}
